/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.hop.ui.hopgui;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.hop.core.database.RunPython;
import org.apache.hop.core.vfs.HopVfs;
import org.apache.hop.ui.core.dialog.BaseDialog;
import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.client.service.UrlLauncher;
import org.eclipse.rap.rwt.widgets.DialogCallback;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;

public class HopGuiRap extends HopGuiTools {
  public static HopGui HOPGUI;

  protected HopGuiRap() {
    super();
    // System.setOut(new PrintStream(System.out, true, StandardCharsets.UTF_8));
  }

  @Override
  public void download(String name, Shell sh) {
    MessageBox box = new MessageBox(sh, SWT.YES | SWT.NO | SWT.ICON_QUESTION);
    box.setText("下载文件");
    box.setMessage("确定要下载当前文件吗？");
    int answer = box.open();
    if ((answer & SWT.YES) != 0) {
      // JavaScriptExecutor executor = RWT.getClient().getService( JavaScriptExecutor.class );
      // executor.execute( script.getText() );
      UrlLauncher launcher = RWT.getClient().getService(UrlLauncher.class);
      // System.out.println(name);
      // 找到 'ROOT' 在字符串中的位置
      int indexOfRoot = name.indexOf("/BOOT-INF/");
      // 如果 'ROOT' 存在于字符串中
      if (indexOfRoot > 0) name = name.substring(indexOfRoot);
      name = "." + name;
      System.out.println(name);
      launcher.openURL(name);
    }
  }

  @Override
  public void load2vect(String dir, Shell sh) {
    MessageBox box = new MessageBox(sh, SWT.YES | SWT.NO | SWT.ICON_QUESTION);
    box.setText("加载到向量库");
    box.setMessage("文件比较多的情况下加载的可能比较慢。确定要把当前文件夹加载到向量库吗？");
    int answer = box.open();
    if ((answer & SWT.YES) == 0) return;
    dir = dir.replace("file:///", "/");
    System.out.println("[bzm]:dir=" + dir);
    try {
      String ret = RunPython.loadRag(dir);
      MessageBox info = new MessageBox(sh);
      info.setMessage(ret);
      info.open();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  @Override
  public void upload(FileObject fileObj, Shell sh) {
    // 上传文件
    FileDialog file = new FileDialog(sh, SWT.TITLE | SWT.RESIZE | SWT.MULTI);
    // FileDialog file = new FileDialog(sh, SWT.TITLE | SWT.RESIZE|S);
    file.setText("upload");
    file.open(
        new DialogCallback() {
          @Override
          public void dialogClosed(int returnCode) {
            if (returnCode == 1) return;
            try {
              showUploadResults(sh, fileObj, file);
            } catch (IOException e) {
              System.out.println(e.getStackTrace());
            }
          }
        });
  }

  private void showUploadResults(Shell sh, FileObject fileObj, FileDialog fileDialog)
      throws IOException {
    String dir = fileObj.getPath().toString();
    if (fileObj.isFile()) {
      dir = fileObj.getParent().getPath().toString();
    }
    String[] selectedFiles = fileDialog.getFileNames();
    for (String fileName : selectedFiles) {
      System.out.println("[showUploadResults]fileName=" + fileName);
      Path source = Path.of(fileName);
      String name = source.getFileName().toString();
      Path destination = Path.of(dir + File.separator + name);
      System.out.println("[showUploadResults]dir=" + dir);
      Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING);
    }
    if (selectedFiles.length == 0) return;
    ExplorerPerspective.getInstance().refresh();
    MessageBox box = new MessageBox(sh);
    box.setMessage("上传成功");
    box.open();
  }

  @Override
  public void aigc(FileObject fileObj, Shell sh) {
    Chatgpt gpt = new Chatgpt(sh, "大模型生成");
    gpt.setFileObj(fileObj);
    gpt.open();
  }

  @Override
  public void agent(FileObject fileObj, Shell sh) {
    // 调用python生成文件夹和文件里面的文件
    final IInputValidator val =
        new IInputValidator() {
          @Override
          public String isValid(final String newText) {
            String result = null;
            if (newText.length() < 5) {
              result = "输入内容不能小于5个字符";
            }
            return result;
          }
        };
    final InputDialog dlg = new InputDialog(sh, "生成Agent", "请输入Agent名称", "LLmAgent", val);
    int returnCode = dlg.open();
    if (returnCode != Window.OK) return;
    String txt = dlg.getValue();
    try {
      String ret = RunPython.runAgent(txt);
      MessageBox info = new MessageBox(sh);
      info.setMessage(ret);
      info.open();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  @Override
  public void rag(FileObject fileObj, Shell sh) {
    ChatRag gpt = new ChatRag(sh, "大模型查找");
    gpt.setFileObj(fileObj);
    gpt.open();
  }

  @Override
  public void copyfile(FileObject fileObj, Shell sh) {
    try {
      final IInputValidator val =
          new IInputValidator() {
            @Override
            public String isValid(final String newText) {
              String result = null;
              if (newText.length() < 3) {
                result = "文件名称太短";
              }
              return result;
            }
          };
      String src = fileObj.getName().getPath();
      String newFile = newFileName(src);
      FileObject dstFile = HopVfs.getFileObject(newFile);
      String dest =
          BaseDialog.presentFileDialog(
              true, sh, null, dstFile, new String[] {"*"}, new String[] {"*"}, true);
      if (dest == null) {
        return;
      }
      dest = HopGuiRap.HOPGUI.getVariables().resolve(dest);
      if (src.equals(dest)) {
        MessageBox box = new MessageBox(sh);
        box.setMessage("复制的文件不能相同");
        box.open();
        return;
      }
      Path source = Path.of(src);
      Path destination = Path.of(dest);
      if (fileObj.isFolder()) {
        copyFolder(source, destination);
      } else {
        Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING);
      }
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * 整个文件夹的复制
   *
   * @param source 文件夹源
   * @param target 文件夹目标
   * @throws IOException
   */
  private void copyFolder(Path source, Path target) throws IOException {
    Files.walkFileTree(
        source,
        new SimpleFileVisitor<Path>() {
          @Override
          public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
              throws IOException {
            Path targetFile = target.resolve(source.relativize(file));
            Files.copy(file, targetFile);
            return FileVisitResult.CONTINUE;
          }

          @Override
          public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
              throws IOException {
            Path targetDir = target.resolve(source.relativize(dir));
            Files.createDirectories(targetDir);
            return FileVisitResult.CONTINUE;
          }
        });
  }

  @Override
  public void movefile(FileObject fileObj, Shell sh) {
    try {
      final IInputValidator val =
          new IInputValidator() {
            @Override
            public String isValid(final String newText) {
              String result = null;
              if (newText.length() < 3) {
                result = "文件名称太短";
              }
              return result;
            }
          };
      String src = fileObj.getName().getPath();
      String newFile = newFileName(src);
      FileObject dstFile = HopVfs.getFileObject(newFile);
      String dest =
          BaseDialog.presentFileDialog(
              true, sh, null, dstFile, new String[] {"*"}, new String[] {"*"}, true);
      if (dest == null) {
        return;
      }
      dest = HopGuiRap.HOPGUI.getVariables().resolve(dest);
      if (src.equals(dest)) {
        MessageBox box = new MessageBox(sh);
        box.setMessage("移动的文件不能相同");
        box.open();
        return;
      }
      Path source = Path.of(src);
      Path destination = Path.of(dest);
      Files.move(source, destination, StandardCopyOption.REPLACE_EXISTING);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * 获取新的文件名
   *
   * @param path 老的文件
   * @return
   */
  private String newFileName(String path) {
    String extension = "";
    String filename = path;
    // 获取当前时间
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm");
    String currentTime = sdf.format(new Date());
    int dotIndex = path.lastIndexOf('.');
    if (dotIndex != -1) {
      extension = path.substring(dotIndex + 1);
      filename = path.substring(0, dotIndex);
      return filename + "-" + currentTime + "." + extension;
    }
    // 在文件名后面加上当前时间
    return filename + "-" + currentTime;
  }

  @Override
  public void openssh(FileObject fileObj, Shell sh) {
    try {
      if (fileObj.isFolder()) {
        MessageBox box = new MessageBox(sh);
        box.setMessage("当前是文件夹，请选择一个文件");
        box.open();
        return;
      }
    } catch (FileSystemException e) {
      throw new RuntimeException(e);
    }
    Webssh gpt = new Webssh(sh, "LLM终端");
    gpt.setFileObj(fileObj);
    gpt.open();
  }

  @Override
  public String runshell(String cmd, String pythonScriptPath, Shell sh) {
    pythonScriptPath = pythonScriptPath.replace("file:///", "/");
    ProcessBuilder processBuilder = new ProcessBuilder(cmd, pythonScriptPath);
    processBuilder.redirectErrorStream(true);
    StringBuilder ret = new StringBuilder();
    MessageBox box = new MessageBox(sh);
    try {
      Process process = processBuilder.start();
      // 读取输出
      BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
      String line;
      while ((line = stdout.readLine()) != null) {
        // System.out.println(line);
        ret.append(line);
      }
      // 等待进程结束
      process.waitFor();
      int exitValue = process.exitValue();
      if (exitValue != 0) {
        box.setMessage("运行错误");
      } else box.setMessage("运行成功");
      stdout.close();
    } catch (Exception e) {
      e.printStackTrace();
      box.setMessage("运行错误");
    }
    box.open();
    System.out.println("[bzm]:ret=" + ret);
    return ret.toString();
  }
}
